#pragma once

/** 关于重复包含的预防：任选一种都可以，推荐pragma写法。
 * 上面的写法更简单，更高效。某些编译器在同一编译单元中，可能都不会再读该头文件。
 * 下面是传统的保护宏写法，优点是移植性更好，缺点是影响编译速度（预处理器仍要扫描文件），
 *    还可能宏名冲突，另外文件开头、结尾都要写也比较麻烦。
*/
#ifndef SDU_ROW_VIEW_HPP
#define SDU_ROW_VIEW_HPP

#include <cstddef>
#include <stdexcept>

namespace sdu {

// 前置声明
template <typename T>
class Matrix;

/**
 * @brief 矩阵“行”的视图类
 */
template<typename T>
class RowView {
  /**
   * @brief 临时性视图，m_vec不允许指向其他位置。
   * 注意const的位置，m_vec所指的数据是可以修改的。
  */
  T* const m_vec;

  /**
   * @brief 列数
  */
  const size_t m_col;

  /**
   * @brief 私有构造函数，不允许外部使用。
   */
  RowView(T* ptr, size_t col) : m_vec(ptr), m_col(col) {}

  // 友元声明，只允许同类型的矩阵类构造行视图。
  friend class Matrix<T>;

public:

  /**
   * @brief 常性下标访问
   * @param col 列索引
   * @return 元素的常性引用。
   * @details 当col大于或等于m_col时，抛出out_of_range异常。
   */
  const T& operator[](const size_t col) const {
    if(col >= m_col) { // TODO: 可以改进为提示具体的索引值和区间范围。
      throw std::out_of_range("Matrix column index out of range.");
    }
    return m_vec[col];
  }

  /**
   * @brief 下标访问元素
   * @param col 列索引
   * @return 元素的引用，可以修改。
   * @details 当col大于或等于m_col时，抛出out_of_range异常。
   */
  T& operator[](const size_t col) {
    if(col >= m_col) { // TODO: 可以改进为提示具体的索引值和区间范围。
      throw std::out_of_range("Matrix column index out of range.");
    }
    return m_vec[col];
  }
};

} // namespace sdu

#endif
